package com.company.eos.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.company.eos.controller.form.amect.*;
import com.company.eos.websocket.WebSocketService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import com.company.eos.common.util.PageUtils;
import com.company.eos.common.R;
import com.company.eos.domain.Amect;
import com.company.eos.service.AmectService;
import com.company.eos.wxpay.WXPayUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 罚款Controller
 *
 * @author: Song, Wei
 * @date: 2022-03-20
 */
@Slf4j
@RestController
@RequestMapping("/amect")
@Tag(name = "罚款模块Web接口")
public class AmectController {

    @Autowired
    private AmectService amectService;

    @Value("${wx.key}")
    private String key;

    @PostMapping("/searchAmectByPage")
    @Operation(summary = "查询罚款分页记录")
    @SaCheckLogin
    public R searchAmectByPage(@Valid @RequestBody SearchAmectByPageForm form) {
        log.info("查询罚款分页记录，参数：{}", form);
        if ((form.getStartDate() != null && form.getEndDate() == null) || (form.getStartDate() == null && form.getEndDate() != null)) {
            return R.error("startDate和endDate只能同时为空，或者不为空");
        }

        Integer page = form.getPage();
        Integer length = form.getLength();
        int start = (page - 1) * length;

        HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
        param.put("start", start);
        param.put("currentUserId", StpUtil.getLoginIdAsInt());
        if (!(StpUtil.hasPermission("AMECT:SELECT") || StpUtil.hasPermission("AMECT:ROOT"))) {
            param.put("userId", StpUtil.getLoginIdAsInt());
        }
        PageUtils pageUtils = amectService.searchAmectByPage(param);

        return R.ok().put("page", pageUtils);
    }

    @PostMapping("/insert")
    @Operation(summary = "添加罚款记录")
    @SaCheckPermission(value = {"ROOT", "AMECT:INSERT"}, mode = SaMode.OR)
    public R insert(@Valid @RequestBody InsertAmectForm form) {
        log.info("添加罚款记录，参数：{}", form);
        ArrayList<Amect> list = new ArrayList<>();
        for (Integer userId : form.getUserId()) {
            Amect amect = new Amect();
            amect.setAmount(new BigDecimal(form.getAmount()));
            amect.setTypeId(Integer.valueOf(form.getTypeId()));
            amect.setReason(form.getReason());
            amect.setUserId(userId);
            amect.setUuid(IdUtil.simpleUUID());
            list.add(amect);
        }
        int rows = amectService.insert(list);
        return R.ok().put("rows", rows);
    }

    @GetMapping("/selectById/{id}")
    @Operation(summary = "根据ID查询罚款记录")
    @SaCheckPermission(value = {"ROOT", "AMECT:SELECT"}, mode = SaMode.OR)
    public R selectById(@Valid @PathVariable("id") @NotNull(message = "id不能为空") int id) {
        log.info("根据ID查询罚款记录，参数：{}", id);
        HashMap map = amectService.selectById(id);
        return R.ok(map);
    }

    @PostMapping("/update")
    @Operation(summary = "更新罚款记录")
    @SaCheckPermission(value = {"ROOT", "AMECT:UPDATE"}, mode = SaMode.OR)
    public R update(@Valid @RequestBody UpdateAmectForm form) {
        log.info("更新罚款记录，参数：{}", form);
        HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
        int rows = amectService.update(param);
        return R.ok().put("rows", rows);
    }

    @DeleteMapping("/deleteAmectByIds")
    @Operation(summary = "删除罚款记录")
    @SaCheckPermission(value = {"ROOT", "AMECT:DELETE"}, mode = SaMode.OR)
    public R deleteAmectByIds(@Valid @RequestBody DeleteAmectByIdsForm form) {
        log.info("删除罚款记录，参数：{}", form);
        int rows = amectService.deleteAmectByIds(form.getIds());
        return R.ok().put("rows", rows);
    }

    @PostMapping("/createNativeAmectPayOrder")
    @Operation(summary = "创建Native支付罚款订单")
    @SaCheckLogin
    public R createNativeAmectPayOrder(@Valid @RequestBody CreateNativeAmectPayOrderForm form) {
        log.info("创建Native支付罚款订单，参数：{}", form);
        int userId = StpUtil.getLoginIdAsInt();
        @NotNull(message = "amectId不能为空") @Min(value = 1, message = "amectId不能小于1") Integer amectId = form.getAmectId();
        HashMap param = new HashMap() {{
            put("amectId", amectId);
            put("userId", userId);
        }};

        String qrCodeBase64 = amectService.createNativeAmectPayOrder(param);
        return R.ok().put("qrCodeBase64", qrCodeBase64);
    }

    @Operation(summary = "接收消息通知")
    @RequestMapping("/recieveMessage")
    public void recieveMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 设置请求字符集
        request.setCharacterEncoding("utf-8");
        Reader reader = request.getReader();
        BufferedReader buffer = new BufferedReader(reader);

        String line = buffer.readLine();
        StringBuffer temp = new StringBuffer();

        while (line != null) {
            temp.append(line);
            line = buffer.readLine();
        }
        buffer.close();
        reader.close();

        String xml = temp.toString();

        // 利用数字证书验证收到的响应内容，避免有人伪造付款接口发送给web方法
        if (WXPayUtil.isSignatureValid(xml, key)) {
            // 将xml数据转换为map
            Map<String, String> map = WXPayUtil.xmlToMap(temp.toString());
            String resultCode = map.get("result_code");
            String returnCode = map.get("return_code");
            // 付款成功
            if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {
                // 获取罚款单uuid
                String outTradeNo = map.get("out_trade_no");
                // 更新订单状态
                HashMap param = new HashMap() {{
                    put("status", 2);
                    put("uuid", outTradeNo);
                }};
                int rows = amectService.updateStatus(param);
                if (rows == 1) {
                    // 向前端推送付款结果
                    int userId = amectService.searchUserIdByUUID(outTradeNo);
                    WebSocketService.sendInfo("收款成功", userId + "");

                    // 给微信平台返回响应
                    response.setCharacterEncoding("utf-8");
                    response.setContentType("application/xml");
                    PrintWriter writer = response.getWriter();
                    BufferedWriter bufferedWriter = new BufferedWriter(writer);
                    bufferedWriter.write("<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>");
                    bufferedWriter.close();
                    writer.close();
                } else {
                    log.error("更新订单状态失败");
                    response.sendError(500, "更新订单状态失败");
                }
            }
        } else {
            log.error("数字签名异常");
            response.sendError(500, "数字签名异常");
        }
    }

    @PostMapping("/searchNativeAmectPayResult")
    @Operation(summary = "查询Native支付罚款订单结果")
    @SaCheckLogin
    public R searchNativeAmectPayResult(@Valid @RequestBody SearchNativeAmectPayResultForm form) {
        int userId = StpUtil.getLoginIdAsInt();
        @NotNull(message = "amectId不能为空") @Min(value = 1, message = "amectId不能小于1") Integer amectId = form.getAmectId();
        HashMap param = new HashMap(3) {{
            put("amectId", amectId);
            put("userId", userId);
            put("status", 1);
        }};
        amectService.searchNativeAmectPayResult(param);
        return R.ok();
    }

    @PostMapping("/searchChart")
    @Operation(summary = "查询Chart图表")
    @SaCheckPermission(value = {"ROOT", "AMECT:SELECT"}, mode = SaMode.OR)
    public R searchChart(@Valid @RequestBody SearchChartForm form) {
        log.info("查询Chart图表，参数：{}", form);
        HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
        HashMap map = amectService.searchChart(param);
        return R.ok(map);
    }
}
